/*
 ============================================================================
 Name		: WSEngine.cpp
 Author	  :
 Version	 : 1.0
 Copyright   : Copyright Genera Software
 Description : CWSEngine implementation
 ============================================================================
 */

#include "WSEngine.h"
#include "WsResponse.h"
#include "ProgressNote.h"
#include "WsObject.h"
#include "ClientEngine.h"
#include "Settings.h"
#include "Globals.h"
#include "WSUtilities.h"
#include "WSRequests.h"
#include "Events.h"
#include "Logger.h"

#include <fieldsstringtable.h>
#include <requestsstringtable.h>
#include <stringloader.h>

const TInt KBufferSize = 512;

CWSEngine::CWSEngine()
    {
    // No implementation required
    }

CWSEngine::~CWSEngine()
    {
    delete iProgressNote;
    delete iHttpClient;
    iStringPool.Close();
    iRequestBuffer.Close();
    iResponseBuffer.Close();
    iAuthorizationString.Close();
    delete iUri;
    delete iJsonGenerator;
    delete iJsonParser;
    }

CWSEngine* CWSEngine::NewLC()
    {
    CWSEngine* self = new ( ELeave ) CWSEngine();
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

CWSEngine* CWSEngine::NewL()
    {
    CWSEngine* self = CWSEngine::NewLC();
    CleanupStack::Pop(); // self;
    return self;
    }

void CWSEngine::ConstructL()
    {
    iStringPool.OpenL( FieldsStringTable::Table );
    iStringPool.OpenL( ReqStringTable::Table );
    iJsonParser = CJsonParser::NewL( FieldsStringTable::Table );
    iJsonGenerator = CJsonGenerator::NewL( FieldsStringTable::Table, EFalse );
    iUri = CUri8::NewL();
    iUri->SetComponentL( KLdirHost, EUriHost );
    iAuthorizationString.CreateL( KNullDesC8 );
    }

//////////////////////////////////////////////////////////////////////////
TBool CWSEngine::GetNextDataPart( TPtrC8& aDataPart )
    {
    //	LOG(EVerbosityWS, _L("CWSEngine::GetNextDataPart() - IN."));
    aDataPart.Set( iRequestBuffer );
    //	LOG(EVerbosityWS, _L("CWSEngine::GetNextDataPart() - OUT."));
    return ETrue;
    }

//////////////////////////////////////////////////////////////////////////
void CWSEngine::ReleaseData()
    {
    //	LOG(EVerbosityWS, _L("CWSEngine::ReleaseData() - IN."));
    //iRequestBuffer.Close();
    // do not release here because if request requires authorization
    // it will be resent and you'll send an empty body
    //	LOG(EVerbosityWS, _L("CWSEngine::ReleaseData() - OUT."));
    }

//////////////////////////////////////////////////////////////////////////
TInt CWSEngine::Reset()
    {
    //	LOG(EVerbosityWS, _L("CWSEngine::Reset() - IN."));
    return KErrNone;
    //	LOG(EVerbosityWS, _L("CWSEngine::Reset() - OUT."));
    }

//////////////////////////////////////////////////////////////////////////
TInt CWSEngine::OverallDataSize()
    {
    //	LOG(EVerbosityWS, _L("CWSEngine::OverallDataSize() - IN."));
    TInt size = iRequestBuffer.Length();
    //	LOG(EVerbosityWS, _L("CWSEngine::OverallDataSize() - OUT."));
    return size;
    }

//////////////////////////////////////////////////////////////////////////
void CWSEngine::ClientEventL( const TInt aEvent )
    {
    LOG(EVerbosityWS, _L("CWSEngine::ClientEventL() - aEvent = %d"), aEvent);
    switch ( aEvent )
        {
        case 1010: // connected to IAP event
            {
            iResponseBuffer.Close();
            iResponseBuffer.CreateL( KBufferSize );
            switch ( iReqType )
                {
                case EHttpGET:
                    iHttpClient->IssueHTTPGetL( iUri->Uri().UriDes(),
                        KJsonContentType, iAuthorizationString, this );
                    break;
                case EHttpPOST:
                    iHttpClient->IssueHTTPPostL( iUri->Uri().UriDes(),
                        KJsonContentType, iAuthorizationString, this );
                    break;
                case EHttpDELETE:
                    iHttpClient->IssueHTTPDeleteL( iUri->Uri().UriDes(),
                        KJsonContentType, iAuthorizationString, this );
                    break;
                default:
                    break;
                }
            }
            break;
        case THTTPEvent::ESucceeded:
            {
            iRequestBuffer.Close();
            delete iHttpClient;
            iHttpClient = NULL;
            iRequestActive = EFalse;
            StopWaitNote();
            HandleWSResponseL();
            }
            break;
        default:
            break;
        }
    }

//////////////////////////////////////////////////////////////////////////
void CWSEngine::ClientErrorL( const TInt aError )
    {
    LOG(EVerbosityWS, _L("CWSEngine::ClientErrorL() - Upload failed, aError = %d"), aError);
    iRequestBuffer.Close();
    delete iHttpClient;
    iHttpClient = NULL;
    iRequestActive = EFalse;
    LOG(EVerbosityWS, _L8("Received buffer: %S"), &iResponseBuffer);
    StopWaitNote();
    if ( aError < 0 )
        {
        CSettings::InstanceL().SetIap( KErrNotFound );
        CSettings::InstanceL().StoreSettingsL();
        }
    iResponseHandler->HandleWsResponseErrorL( iCurrentWSRequest, aError );
    iResponseBuffer.Close();
    LOG(EVerbosityWS, _L("CWSEngine::ClientErrorL() - OUT"));
    }

//////////////////////////////////////////////////////////////////////////
void CWSEngine::ClientBodyReceivedL( const TDesC8& aBodyData )
    {
    LOG(EVerbosityWS, _L("CWSEngine::ClientBodyReceived() - IN."));
    TInt freeLength = iResponseBuffer.MaxLength() - iResponseBuffer.Length();
    if ( freeLength < aBodyData.Length() )
        {
        iResponseBuffer.ReAlloc( iResponseBuffer.MaxLength()
            + aBodyData.Length() - freeLength );
        }
    iResponseBuffer.Append( aBodyData );
    LOG(EVerbosityWS, _L8("Web service response: %S"), &iResponseBuffer);

    LOG(EVerbosityWS, _L("CWSEngine::ClientBodyReceived() - OUT."));
    }

//////////////////////////////////////////////////////////////////////////
void CWSEngine::CancelledL()
    {
    iRequestActive = EFalse;
    }

//////////////////////////////////////////////////////////////////////////
const TDesC8& CWSEngine::GenerateUriL( const TWSRequest& aRequest,
    const TDesC8& aParam )
    {
    LOG(EVerbosityWS, _L("CWSEngine::GenerateUriL() - IN."));
    if ( aRequest.iSecure )
        iUri->SetComponentL( KHttps, EUriScheme );
    else
        iUri->SetComponentL( KHttp, EUriScheme );

    TBuf8<KMaxPath> path;
    //path = KWSVersion;
    RString reqPath = iStringPool.String( aRequest.iResourceStringIndex,
        ReqStringTable::Table );

    if ( aRequest.iNeedsParam && aParam != KNullDesC8 )
        path.AppendFormat( reqPath.DesC(), &aParam );
    else
        path.Append( reqPath.DesC() );

    iUri->SetComponentL( path, EUriPath );

    LOG(EVerbosityWS, _L("CWSEngine::GenerateUriL() - OUT."));
    return iUri->Uri().UriDes();
    }

void CWSEngine::WSRequestL( const TInt aRequestID, MWsObject* aReqObject,
    const TDesC8& aAdditionalParam, const TInt aResId,
    MWsResponseHandler* aResponseHandler )
    {
    if ( iRequestActive )
        return;

    TWSRequest request;
    iCurrentWSRequest = aRequestID;
    request = *GetRequestById( aRequestID );
    iReqType = request.iHttpType;
    GenerateUriL( request, aAdditionalParam );

    iRequestBuffer.Close();
    iResponseHandler = aResponseHandler;

    if ( aReqObject )
        {
        iRequestBuffer.Assign( aReqObject->EncodeL( *iJsonGenerator ) );
        if ( iRequestBuffer.Length() )
            {
            LOG(
                EVerbosityWS,
                _L8("CWSEngine::WSRequestL() - aReqId = %d, requestBuffer:"), aRequestID);
            LOGBUFFER(iRequestBuffer);
            }
        }

    iHttpClient = CHttpClient::NewL( *this );
    iHttpClient->ConnectL();

    StartWaitNoteL( aResId );
    }

////////////////////////////////////////////////////////////////////////////////
void CWSEngine::HandleWSResponseL()
    {
    if ( iResponseHandler )
        {
        CWsResponse* wsResponse = CWsResponse::NewLC();
        wsResponse->DecodeL( iResponseBuffer, *iJsonParser );

        iResponseHandler->HandleWsResponseL( iCurrentWSRequest, KErrNone,
            wsResponse );

        CleanupStack::PopAndDestroy( wsResponse );
        }
    iResponseBuffer.Close();
    }

////////////////////////////////////////////////////////////////////////////////
void CWSEngine::StartWaitNoteL( const TInt aResId )
    {
    if ( iProgressNote )
        delete iProgressNote;
    iProgressNote = CProgressNote::NewL();
    iProgressNote->DismissedByUser += MAKEMETHODEVENTHANDLER0( void, CWSEngine,
        HandleProgressDismissedByUser, this );
    HBufC* text = StringLoader::LoadLC( aResId );
    iProgressNote->StartWaitNoteL( *text );
    CleanupStack::PopAndDestroy( text );
    }

////////////////////////////////////////////////////////////////////////////////
void CWSEngine::StopWaitNote()
    {
    delete iProgressNote;
    iProgressNote = NULL;
    }

////////////////////////////////////////////////////////////////////////////////
void CWSEngine::HandleProgressDismissedByUser()
    {
    CancelWsRequest();
    }

////////////////////////////////////////////////////////////////////////////////
TBool CWSEngine::IsActive()
    {
    return iRequestActive;
    }

////////////////////////////////////////////////////////////////////////////////
void CWSEngine::CancelWsRequest()
    {
    if ( !iRequestActive )
        return;
    iHttpClient->CancelTransaction();
    }
